home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
3D GFX
/
3D GFX.iso
/
amiutils
/
m_p
/
photocdaga
/
developer
/
encodeham.asm
next >
Wrap
Assembly Source File
|
1995-12-30
|
19KB
|
470 lines
; ppm2AGA utility functions written by Gⁿnther R÷hrich
; the version for 68020+ processors is slightly faster and smaller
; the function is called from C:
; EncodeHAM(char *yorig, char *yham, char *ColorTable,
; short NumColors, short xsize);
; yorig = original row in rgbrgb... format
; yham = row in HAM chunky format
; ColorTable = color table in brgbrg... format
; NumColors = (number of valid colors in ColorTable)*3
; xsize = size of row in pixels
; ConvertMode should contain: 0 for HAM6 encoding
; 1 for HAM8 encoding
; int MapColor(colorhist_vector colormap, pixval r1, pixval g1, pixval b1,
; int NumColors)
; see later
IFD MC68020
MACHINE MC68020
ENDC
IFD MC68000
MACHINE MC68000
ENDC
;NOTE: GCC stores all data as 32 bit at subroutine calls!
yorig EQU 44 ;pointer to actual row (original)
yham EQU 48 ;pointer to actual row (HAM)
ColorTable EQU 52 ;address of color table (3 bytes per entry)
IFD GCC
NumColors EQU 58
xsize EQU 62
ELSE
NumColors EQU 56 ;number of colors allocated so far (*3)
xsize EQU 58 ;number of pixels (x)
ENDC
colormap EQU 44 ;pointer to colorhist_vector
IFD GCC
r1 EQU 51
g1 EQU 55
b1 EQU 59
NColors EQU 60
ELSE
r1 EQU 48 ;red component (byte format)
g1 EQU 50 ;green component
b1 EQU 52 ;blue component
NColors EQU 54 ;number of colors in colormap
ENDC
XREF _Mult_Table ;address of multiplication table
XREF _Mult_Table32
XREF _ConvertMode ;HAM8 or HAM6
XDEF _EncodeHAM ;entry point for function
XDEF _MapColorASM
XREF _ColorCache ;an 256K array
* XDEF _blue_left ;only for debugging purposes
* XDEF _search_finish ;only for debugging
XDEF _MaxError
XDEF _MaxErrorPos
XDEF _hit ;only for debugging
XDEF _t1 ;only for debugging
dseg
cnop 0,2
_blue_left: dc.b 0 ;this order is better for HAM-encoding
_red_left: dc.b 0
_green_left: dc.b 0,0 ;additional dummy-value for faster longword access
cnop 0,2
_offset_orig: dc.w 0
_offset_ham: dc.w 0
_MaxError: dc.w 0
_MaxErrorPos dc.w 0
_CacheOffset dc.l 0
_colcount dc.w 2
cseg
;register usage: D0 = general purpose register
; D1 = contains afterwards the error
; D2 = orig_blue
; D3 = orig_red
; D4 = orig_green
; D5 = color that should be set
; D6 = offset to actual pixel (HAM)
; D7 = offset for color table / (0,1,2) at HAM
; A0 = best color so far (color+1)*3
; A1 = pointer to multiplication table
; A2 = pointer to color table / to _blue_left
; A3 = smallest error that has been reached so far
; A4 = used by the Aztec assembler (small data model)
; A5 = pointer to the actual row (original)
; A6 = pointer to the actual row (HAM)
;WARNING: This will not work with color values higher than 63
;(HAM8 has a maximum of 63, HAM6 has a maximum of 15)
;(values higher than 63 may result in memory corruption)
;computing the difference of color values is done with signed 8 bit
;arithmetic
;the maximum error value is 63^2+63^2+63^2=11907
;the summation has to be done therefore with 16 bits
;Initializing
_EncodeHAM: movem.l D2-D7/A2-A3/A5/A6,-(A7) ;store registers
lea _blue_left,A0 ;load start of left colors
move.l ColorTable(sp),A2
IFD MC68020
move.l (A2),(A0)
ELSE
move.b (A2)+,(A0)+ ;initialize left colors
move.b (A2)+,(A0)+ ;A2 may not be word aligned
move.b (A2)+,(A0)+
lea -3(A0),A0 ;correct register
lea -3(A2),A2 ;correct register
ENDC
moveq.l #0,D6 ;initialize ham offset
move.l D6,_MaxError ;initialize absolute max error
;and max error pos
move.l yham(sp),A6
move.l yorig(sp),A5
lea _Mult_Table,A1
lea 255*2(A1),A1
search_begin: move.b (A5)+,D3 ;load registers with original colors
move.b (A5)+,D4 ;for faster access
move.b (A5)+,D2
IFD GCC
lea 1(A5),A5 ;adjust A5 for correct alignment
ENDC ;needed for GNU C
move.w #15000,A3 ;dummy-value for minimum error so far
move.l ColorTable(sp),A2
moveq.l #0,D7 ;initialize offset for color table
;find out if the new pixel has the same color as the previous one
lea _blue_left,A0
cmp.b (A0),D2
bne.s search_cont
cmp.b 1(A0),D3
bne.s search_cont
cmp.b 2(A0),D4
bne.s search_cont
;the new pixel has the same color, let's do a special encoding
move.w _colcount,D7
move.b 0(A0,D7.w),D5
subq.w #1,_colcount
bpl.s ham6_9
move.w #2,_colcount
bra.s ham6_9
;First take a look if we have the value already in the cache
search_cont: moveq.l #0,D0
moveq.l #0,D1
move.b D3,D0 ;compute the cache offset
lsl.l #6,D0
or.b D4,D0
lsl.l #6,D0
or.b D2,D0 ;now we have the offset in D0
movea.l _ColorCache,A0 ;load start address of the cache
move.b 0(A0,D0.l),D1 ;take the value from the cache
bne _hit ;jump if we have a cache hit
move.l D0,_CacheOffset ;store the offset to avoid recomputing it
move.l #3,A0 ;dummy-value for best colornumber so far
; (3 means color 0)
search_start: bsr _compute_error
cmp.w D1,A3 ;A3 <= D1 ?
bls.s search4
move.w D1,A3 ;D1 is smaller than A3, store it
move.w D7,A0 ;store color number
tst.w D1 ;do we have the correct color ?
beq search5 ;then finish immediately
search4: cmp.w NumColors(sp),D7 ;have we reached highest colornum ?
bne.s search_start ;no, then once again
;A0 contains now (colornumber+1)*3
;A3 contains the error for that colornumber
_t1: move.w A0,D0
movea.l _ColorCache,A2
move.l _CacheOffset,D1
move.b D0,0(A2,D1.l) ;store the value in the cache
lea _blue_left,A2 ;restore A2
;compute the error when using modify mode
start_ham6: move.b D2,D0 ;load orig_blue
moveq.l #0,D7 ;assume blue should be changed
move.b D2,D5 ;store value to change
sub.b _blue_left,D0 ;D0=D0-_blue_left
bpl.s ham6_1
neg.b D0 ;make result positive
ham6_1: move.b D0,D1 ;store maximum error so far
move.b D3,D0 ;load orig_red
sub.b _red_left,D0 ;D0=D0-_red_left
bpl.s ham6_2
neg.b D0
ham6_2: cmp.b D0,D1 ;check D1-D0
bge.s ham6_3 ;jump if D1>=D0
move.b D0,D1 ;store new maximum error
moveq.l #1,D7 ;assume red should be changed
move.b D3,D5 ;store value to change
ham6_3: move.b D4,D0 ;load orig_green
sub.b _green_left,D0 ;D0=D0-_green_left
bpl.s ham6_4
neg.b D0
ham6_4: cmp.b D0,D1
bge.s ham6_5
move.b D0,D1 ;store maximum error
moveq.l #2,D7 ;green should be changed
move.b D4,D5 ;store value to change
ham6_5: lea _blue_left,A2
move.b D5,0(A2,D7.W) ;perform change
ham_error: moveq.l #0,D1
moveq.l #0,D0
move.b D2,D0 ;load blue_origin
sub.b (A2)+,D0 ;D0 = blue_color - blue_origin
ext.w D0
IFD MC68020
add.w 0(A1,D0.W*2),D1
ELSE
add.w D0,D0
add.w 0(A1,D0.W),D1 ;D1 = D1 + D0*D0
ENDC
move.b D3,D0 ;load red_origin
sub.b (A2)+,D0 ;D0 = red_color - red_origin
ext.w D0
IFD MC68020
add.w 0(A1,D0.W*2),D1
ELSE
add.w D0,D0
add.w 0(A1,D0.W),D1
ENDC
move.b D4,D0 ;load green_origin
sub.b (A2)+,D0 ;D0 = green_color - green_origin
ext.w D0
IFD MC68020
add.w 0(A1,D0.W*2),D1
ELSE
add.w D0,D0
add.w 0(A1,D0.W),D1 ;D1 contains error from HAM encoding
ENDC
cmpa.w D1,A3 ;check what error is smaller
bls.s _search_finish ;jump if colortable is better
cmp.w _MaxError,D1 ;compare with absolute max error
ble.s ham6_9 ;jump if _MaxError is greater
cmp.w #2,D6 ;less then 2 pixels from left ?
bpl.s ham6_8a
lsr.w #1,D1 ;half error
ham6_8a: move.w D1,_MaxError
move.w D6,_MaxErrorPos
ham6_9: add.b #1,D7 ;needed to get correct code
tst.w _ConvertMode ;ConvertMode = 0 -> HAM6
beq.s ham6_10 ;ConvertMode != 0 -> HAM8
IFD MC68020
lsl.b #2,D7 ;HAM8-adjust
ELSE
add.b D7,D7 ;this is faster than shifting
add.b D7,D7 ;on the 68000
ENDC
ham6_10: lsl.b #4,D7 ;HAM6-adjust
or.b D5,D7
move.b D7,(A6,D6.W) ;store code in bitmap
addq.w #1,D6 ;increase _offset_ham
cmp.w xsize(sp),D6 ;end of column ?
bne search_begin
bra.s search_end
_search_finish: move.w A3,D0 ;move error to D0
cmp.w #2,D6 ;less then 2 pixels from left ?
bpl.s _search_finish1
lsr.w #1,D0 ;half error
_search_finish1: cmp.w _MaxError,D0 ;compare with absolute max error
ble.s _search_finish2
move.w D0,_MaxError
move.w D6,_MaxErrorPos
_search_finish2: move.w A0,D0
move.l ColorTable(sp),A2
lea -3(A2,D0.W),A3 ;load A3 with pointer to colors
divu #3,D0
subq.w #1,D0
move.b D0,0(A6,D6.W) ;store colornumber in bitmap
lea _blue_left,A2
IFD MC68020
move.l (A3),(A2)
ELSE
move.b (A3)+,(A2)+ ;store new left colors
move.b (A3)+,(A2)+ ;A3 may not be word aligned
move.b (A3)+,(A2)+ ;
ENDC
addq.w #1,D6 ;increase _offset_ham
cmp.w xsize(sp),D6 ;have we reached the end ?
bne search_begin
search_end: movem.l (A7)+,D2-D7/A2-A3/A5/A6 ;restore registers
rts ;jump back to caller
;we jump here if we have reached error 0 by colortable only
;and there was not a cache hit
search5: move.w A0,D0
movea.l _ColorCache,A2
move.l _CacheOffset,D1
move.b D0,0(A2,D1.l) ;store the value in the cache
bra.s _search_finish
;we jump here if we have a cache hit
;D1 contains the best color number, but we have to compute the error
_hit: subq.w #3,D1 ;correct color number
move.w D1,D7
bsr.s _compute_error
move.w D1,A3 ;D1 is smaller than A3, store it
move.w D7,A0 ;store color number
bra start_ham6 ;continue with HAM encoding
;compute the error
_compute_error: moveq.l #0,D1
moveq.l #0,D0
move.b D2,D0 ;load blue_origin
sub.b 0(A2,D7.W),D0 ;D0 = blue_color - blue_origin
ext.w D0 ;extend result to word
IFD MC68020
add.w 0(A1,D0.W*2),D1
ELSE
add.w D0,D0
add.w 0(A1,D0.W),D1 ;D1 = D1 + D0*D0
ENDC
addq.w #1,D7 ;advance color table offset
move.b D3,D0 ;load red_origin
sub.b 0(A2,D7.W),D0 ;D0 = red_color - red_origin
ext.w D0
IFD MC68020
add.w 0(A1,D0.W*2),D1
ELSE
add.w D0,D0
add.w 0(A1,D0.W),D1
ENDC
addq.w #1,D7 ;advance color table offset
move.b D4,D0 ;load green_origin
sub.b 0(A2,D7.W),D0 ;D0 = green_color - green_origin
ext.w D0
IFD MC68020
add.w 0(A1,D0.W*2),D1 ;D1 = D1 + D0*D0
ELSE
add.w D0,D0
add.w 0(A1,D0.W),D1
ENDC
addq.w #1,D7 ;advance color table offset
rts
;now comes the brute-force colormap search code
;if you know how to make it faster/smaller please let me know
;the 68020 main loop is only 56 bytes long, it should
;fit completely into the 256 bytes instruction cache of the 68020
;or 68030 processor
;NOTE: this is a bit different compared to the HAM-code because
;signed 8 bit math gives wrong results with values higher than 127
;it computes the differences therefore with 16 bit
;the maximum error value is 3*255^2=195075, we will therefore need
;32 bit arithmetic for the summation
;register usage:
; D0 = general purpose register, return value
; D1 = contains error
; D2 = r1
; D3 = g1
; D4 = b1
; D5 = holds color from colormap
; D6 = counter
; D7 = color table offset
; A1 = pointer to multiplication table
; A2 = pointer to colormap
; A3 = smallest error
; A5 = actual error
; A6 = NColors
_MapColorASM: movem.l D2-D7/A2-A3/A5/A6,-(A7) ;store registers
move.l colormap(sp),A2
move.l NColors(sp),A6
lea _Mult_Table32,A1
lea 255*4(A1),A1
moveq.l #0,D2 ;ensure that the higher bytes
moveq.l #0,D3 ;of these registers are cleared
moveq.l #0,D4
move.b r1(sp),D2
move.b g1(sp),D3
move.b b1(sp),D4
move.l #2000000000,A3 ;dummy value for min. error
moveq.l #0,D6 ;initialize counter
moveq.l #0,D7
moveq.l #0,D5
;now comes the main loop
Map_start: suba.l A5,A5 ;clear A5 (actual error)
move.l D2,D0 ;load r1
move.b 0(A2,D7.W),D5 ;load colormap.red
sub.w D5,D0 ;D0 = colormap.red - r1
IFD MC68020
add.l 0(A1,D0.W*4),A5
ELSE
lsl.w #2,D0
add.l 0(A1,D0.W),A5 ;A5 = A5 + D0*D0
ENDC
move.l D3,D0 ;load g1
move.b 1(A2,D7.W),D5 ;load colormap.green
sub.w D5,D0 ;D5 = colormap.green - g1
IFD MC68020
add.l 0(A1,D0.W*4),A5
ELSE
lsl.w #2,D0
add.l 0(A1,D0.W),A5
ENDC
move.l D4,D0 ;load b1
move.b 2(A2,D7.W),D5 ;load colormap.blue
sub.w D5,D0 ;D0 = colormap.blue - b1
IFD MC68020
add.l 0(A1,D0.W*4),A5 ;A5 = A5 + D0*D0
ELSE
lsl.w #2,D0
add.l 0(A1,D0.W),A5
ENDC
addq.w #8,D7 ;advance color table offset
cmp.l A5,A3 ;A3 - A5 ?
bls.s Map1
move.l A5,A3 ;D1 is smaller than A3, store it
move.w D6,A0 ;store color number
move.l A5,D0 ;do we have the correct color ?
beq.s Map_finish ;then finish immediately
Map1: addq.w #1,D6 ;advance color number
cmp.l A6,D6 ;have we reached highest colornum ?
bne.s Map_start ;no, then once again
Map_finish: move.l A0,D0 ;store return value
movem.l (A7)+,D2-D7/A2-A3/A5/A6 ;restore registers
rts ;jump back to caller
end